/*
 * Client.cpp
 *
 *   Created on: 2010-3-28     
 *  Description: 
 *    Copyright: 2010 @ ICT Li Heyuan
 */

#include "../../include/client/Client.h"
#include "../../include/json_cpp/json.h"
#include "../../include/util/Const.h"
using Json::Value;

#include <string>
#include <iostream>
#include <stdexcept>
using std::cout;
using std::endl;
using std::string;
using std::runtime_error;

bool Client::call(std::string method, Value &param, Value &ret,
		unsigned int timeout)
{
	//step1 call(获取RSA公钥)
	string error, jsonReq;
	if (!autoEncrypt(method, param, jsonReq, error))
	{
		ret = error;
		return false;
	}//end if auto加密失败
	else
	{
		//执行Step 2 Call
		if (!_call(jsonReq, ret, timeout))
		{
			return false;
		}//if step2 call 失败
		else
		{
			//解密result，写回到参数中
			string error;
			if (!autoDecrypt(ret, error))
			{
				//解密失败
				ret = error;
				return false;
			}
			else
			{
				//解密成功
				return true;
			}
		}//if Step2 call success
	}//end if auto加密成功
}

bool Client::notification(std::string method, Value &param,
		unsigned int timeout)
{
	//step1 call(获取RSA公钥)
	string error, jsonReq;
	if (!autoEncrypt(method, param, jsonReq, error, false))
	{
		//		ret = error;
		return false;
	}//end if step1 失败
	else
	{
		//执行Step 2 notification
		if (!_notification(jsonReq, timeout))
		{
			return false;
		}//if step2 call 失败
		else
		{
			//notification没有response，无需解密
			return true;
		}//if Step2 notification success
	}//end if step1 成功
}

bool Client::autoEncrypt(std::string method, Value &param, string &jsonReq,
		string &error, bool response)
{
	Json::FastWriter writer;
	if (!_isEncrypt)//不需要加密，直接返回
	{
		Json::Value req;
		if (response)
		{
			req[Const::ID] = 1;//@TODO
		}
		else
		{
			req[Const::ID] = Json::nullValue;
		}
		req[Const::PARAMS] = param;
		req[Const::METHOD] = method;
		jsonReq = writer.write(req);
		return true;
	}

	//准备step1 call的json-rpc串
	Json::Value req, ret;
	req[Const::ID] = 1;//@TODO
	req[Const::METHOD] = Const::SYS_RSA_PUBKEY;
	req[Const::PARAMS] = Json::nullValue;
	string req1 = writer.write(req);

	//执行step1:获取public_key
	if (!_call(req1, ret))
	{
		error = ret.asString() + "during get RSA_PUB_KEY.";
		return false;
	}//if rpc_call(SYS_RSA_PUBKEY) fail
	else
	{
		//成功获取了key 格式E \t N
		string ret_str = ret.asString();

		//检查key格式是否正确
		string::size_type pos = ret_str.find('\t');
		if (pos == string::npos)
		{
			error = "rsa_public_key format error.";
			return false;
		}//end if pub_key格式错误
		else//if 格式正确
		{
			try
			{
				//基本属性
				if (response)
				{
					req[Const::ID] = 1;//@TODO
				}
				else
				{
					req[Const::ID] = Json::nullValue;
				}
				req[Const::METHOD] = method;

				//格式正确，切分，生成RSATools
				string E = ret_str.substr(0, pos);
				string N = ret_str.substr(pos + 1);

				//使用RSA把AES的key加密，并写入jsonReq中
				_rsa = RSATools(E, N);
				req[Const::AES_KEY] = Value(_rsa.encryptWithBase64(
						_aes.getKey()));

				//将params使用AES加密，写入jsonReq中
				string param_plain = writer.write(param);
				cout << param_plain;
				string param_cipher = _aes.encryptWithBase64(param_plain);
				req[Const::PARAMS] = Value(param_cipher);
				jsonReq = writer.write(req);

				return true;
			} catch (runtime_error &exception)
			{
				error = exception.what();
				return false;
			} catch (...)
			{
				error = "RSA encrypt fail.";
				return false;
			}
		}//end if 格式正确
	}//end if rpc_call(SYS_RSA_PUBKEY) success
}

bool Client::autoDecrypt(Value &ret, string &error)
{
	//不需要加密，直接返回
	if (!_isEncrypt)
	{
		return true;
	}

	try
	{
		string ret_cipher = ret.asString();//加密的，肯定不是object
		string ret_plain = _aes.decryptWithBase64(ret_cipher);

		Json::Reader reader;
		reader.parse(ret_plain, ret, false);
		return true;
	} catch (runtime_error &exception)
	{
		error = exception.what();
		return false;
	} catch (...)
	{
		error = "AES decrypt fail.";//@TODO,记录key
		return false;
	}
}

void Client::setEncrypt(bool en)
{
	_isEncrypt = en;
}

void Client::setCloseFirst(bool first)
{
	_closeFirst = first;
}
